package com.example.graduationdesign.algorithm;

import com.example.graduationdesign.pojo.dao.WordDao;
import lombok.Data;

import java.sql.*;
import java.util.*;
import java.util.stream.Collectors;

@Data
public class WordRecommendationSystem {

    // 数据库连接配置
    private static final String DB_URL = "jdbc:mysql://localhost:3306/english_study?serverTimezone=Asia/Shanghai&characterEncoding=utf8&allowMultiQueries=true";
    private static final String DB_USER = "root";
    private static final String DB_PASSWORD = "1234";

    // 推荐单词数量（动态变量）
    private int recommendationCount = 10; // 默认值为10

    // 权重配置 - 普通用户
    private static final double MISTAKE_WEIGHT = 0.6;
    private static final double STAGE_WEIGHT = 0.2;
    private static final double DIFFICULTY_WEIGHT = 0.1;
    private static final double FAMILIARITY_WEIGHT = 0.1;

    // 权重配置 - VIP用户 (增加了更多指标)
    private static final double VIP_MISTAKE_WEIGHT = 0.4;
    private static final double VIP_STAGE_WEIGHT = 0.15;
    private static final double VIP_DIFFICULTY_WEIGHT = 0.15;
    private static final double VIP_FAMILIARITY_WEIGHT = 0.1;
    private static final double VIP_RECITE_WEIGHT = 0.1;    // 默写记录权重
    private static final double VIP_CHECKIN_WEIGHT = 0.05;  // 打卡记录权重
    private static final double VIP_GAME_LEVEL_WEIGHT = 0.05; // 游戏关卡权重

    /**
     * 获取用户当前阶段的单词
     * @param userId 用户ID
     * @return 当前阶段的单词列表
     */
    private List<WordDao> getWordsByCurrentStage(long userId) {
        // 1. 获取用户当前阶段
        UserInfo userInfo = getUserInfo(userId);
        if (userInfo == null) {
            return Collections.emptyList();
        }
        int currentStage = userInfo.getStage();

        // 2. 构建SQL查询（只查询当前阶段）
        String sql = "SELECT * FROM wordlist WHERE word_stage = ?";
        List<WordDao> words = new ArrayList<>();

        try (Connection conn = DriverManager.getConnection(DB_URL, DB_USER, DB_PASSWORD);
             PreparedStatement stmt = conn.prepareStatement(sql)) {

            stmt.setInt(1, currentStage);

            ResultSet rs = stmt.executeQuery();

            while (rs.next()) {
                WordDao word = new WordDao();
                word.setCode(rs.getLong("code"));
                word.setWord(rs.getString("word"));
                word.setPhonetic(rs.getString("phonetic"));
                word.setPronunciation(rs.getString("pronunciation"));
                word.setInterpretation(rs.getString("interpretation"));
                word.setSplit(rs.getString("split"));
                word.setSynthesis(rs.getString("synthesis"));
                word.setAssociative(rs.getString("associative"));
                word.setExample(rs.getString("example"));
                word.setTranslate(rs.getString("translate"));
                word.setIsStudyed(rs.getObject("is_studyed", Integer.class));
                word.setIsFamilarized(rs.getObject("is_familarized", Integer.class));
                word.setWordDifficulty(rs.getInt("word_difficulty"));
                word.setWordStage(rs.getInt("word_stage"));

                words.add(word);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return words;
    }

    /**
     * 获取推荐单词
     * @param userId 用户ID
     * @param count 推荐数量
     * @return 推荐单词列表
     */
    public List<WordDao> getRecommendedWords(long userId, Integer count) {
        // 如果传入的count不为null，则使用传入的值，否则使用默认值
        this.recommendationCount = (count != null) ? count : this.recommendationCount;
        // 1. 获取用户基本信息
        UserInfo userInfo = getUserInfo(userId);
        if (userInfo == null) {
            return Collections.emptyList();
        }
        // 2. 获取用户学习记录
        List<StudyRecord> studyRecords = getStudyRecords(userId);
        // 3. 获取用户错误单词(未掌握的)
        List<Long> mistakeWordCodes = getUnmasteredMistakeWords(userId);
        // 4. 获取用户正确单词(已掌握的)
        List<Long> masteredWordCodes = getMasteredWords(userId);
        // 5. 获取当前阶段的单词
        List<WordDao> currentStageWords = getWordsByCurrentStage(userId);
        // 6. 检查是否所有单词都已被掌握
        if (allWordsMastered(currentStageWords, masteredWordCodes)) {
            // 重置测试记录，重新开始
            resetTestRecords(userId);
            masteredWordCodes.clear();
            mistakeWordCodes.clear();
        }
        // 7. 计算所有单词的推荐分数
        Map<Long, Double> wordScores = calculateWordScores(currentStageWords, 
                userInfo, studyRecords, mistakeWordCodes);
        System.out.println(wordScores);
        // 8. 优先推荐未掌握的错误单词，然后是未测试单词，最后是已掌握单词
        List<WordDao> recommendedWords = new ArrayList<>();
        // 先添加未掌握的错误单词并按分数排序
        List<WordDao> unmasteredMistakeWords = currentStageWords.stream()
                .filter(word -> mistakeWordCodes.contains(word.getCode()))
                .sorted(Comparator.comparingDouble(
                        (WordDao w) -> -wordScores.getOrDefault(w.getCode(), 0.0)))
                .collect(Collectors.toList());
        recommendedWords.addAll(unmasteredMistakeWords);
        // 如果错误单词不足，添加未测试单词并按分数排序
        if (recommendedWords.size() < recommendationCount) {
            List<WordDao> untestedWords = currentStageWords.stream()
                    .filter(word -> !masteredWordCodes.contains(word.getCode()) &&
                            !mistakeWordCodes.contains(word.getCode()))
                    .sorted(Comparator.comparingDouble(
                            (WordDao w) -> -wordScores.getOrDefault(w.getCode(), 0.0)))
                    .collect(Collectors.toList());
            recommendedWords.addAll(untestedWords);
        }
        // 如果还不够，添加已掌握单词并按分数排序
        if (recommendedWords.size() < recommendationCount) {
            List<WordDao> masteredWords = currentStageWords.stream()
                    .filter(word -> masteredWordCodes.contains(word.getCode()))
                    .sorted(Comparator.comparingDouble(
                            (WordDao w) -> -wordScores.getOrDefault(w.getCode(), 0.0)))
                    .collect(Collectors.toList());
            recommendedWords.addAll(masteredWords);
        }
        // 9. 返回前recommendationCount个单词
        return recommendedWords.stream()
                .limit(recommendationCount)
                .collect(Collectors.toList());
    }

    /**
     * 检查是否所有单词都已被掌握
     */
    private boolean allWordsMastered(List<WordDao> currentStageWords,
                                     List<Long> masteredWordCodes) {
        if (currentStageWords.isEmpty()) {
            return false;
        }

        Set<Long> currentStageWordCodes = currentStageWords.stream()
                .map(WordDao::getCode)
                .collect(Collectors.toSet());

        return masteredWordCodes.containsAll(currentStageWordCodes);
    }

    /**
     * 重置用户的测试记录
     */
    private void resetTestRecords(long userId) {
        String sql = "DELETE FROM testrecord WHERE testrecord_consumer_id = ?";

        try (Connection conn = DriverManager.getConnection(DB_URL, DB_USER, DB_PASSWORD);
             PreparedStatement stmt = conn.prepareStatement(sql)) {

            stmt.setLong(1, userId);
            stmt.executeUpdate();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取用户已掌握的单词列表
     */
    private List<Long> getMasteredWords(long userId) {
        List<Long> masteredWords = new ArrayList<>();
        String sql = "SELECT DISTINCT testrecord_code FROM testrecord " +
                "WHERE testrecord_consumer_id = ? AND testrecord_is_mastered = 1";

        try (Connection conn = DriverManager.getConnection(DB_URL, DB_USER, DB_PASSWORD);
             PreparedStatement stmt = conn.prepareStatement(sql)) {

            stmt.setLong(1, userId);
            ResultSet rs = stmt.executeQuery();

            while (rs.next()) {
                masteredWords.add(rs.getLong("testrecord_code"));
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return masteredWords;
    }

    /**
     * 获取用户未掌握的错误单词列表
     */
    private List<Long> getUnmasteredMistakeWords(long userId) {
        List<Long> mistakeWords = new ArrayList<>();
        // 获取最近30天的错误单词且未掌握的
        String sql = "SELECT DISTINCT testrecord_code FROM testrecord " +
                "WHERE testrecord_consumer_id = ? AND testrecord_is_true = 0 " +
                "AND testrecord_is_mastered = 0 " +
                "AND testrecord_time >= DATE_SUB(NOW(), INTERVAL 30 DAY)";

        try (Connection conn = DriverManager.getConnection(DB_URL, DB_USER, DB_PASSWORD);
             PreparedStatement stmt = conn.prepareStatement(sql)) {

            stmt.setLong(1, userId);
            ResultSet rs = stmt.executeQuery();

            while (rs.next()) {
                mistakeWords.add(rs.getLong("testrecord_code"));
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return mistakeWords;
    }

    /**
     * 计算单词推荐分数
     */
    private Map<Long, Double> calculateWordScores(List<WordDao> words, UserInfo userInfo,
                                                  List<StudyRecord> studyRecords, List<Long> mistakeWordCodes) {
        Map<Long, Double> scores = new HashMap<>();
        Map<Long, StudyRecord> studyRecordMap = studyRecords.stream()
                .collect(Collectors.toMap(StudyRecord::getWordCode, r -> r));

        // VIP用户特有的数据
        Map<Long, ReciteInfo> reciteInfoMap = userInfo.isVip() ? getReciteInfo(userInfo.getUserId()) : Collections.emptyMap();
        Map<Long, CheckInInfo> checkInInfoMap = userInfo.isVip() ? getCheckInInfo(userInfo.getUserId()) : Collections.emptyMap();

        for (WordDao word : words) {
            double score = 0.0;

            // 1. 错误单词加分 (用户之前错误且未掌握的单词)
            double mistakeScore = mistakeWordCodes.contains(word.getCode()) ? 1.0 : 0.0;

            // 2. 阶段匹配度
            double stageScore = calculateStageScore(word, userInfo.getStage());

            // 3. 难度分数 (优先推荐适合当前用户的难度)
            double difficultyScore = calculateDifficultyScore(word, userInfo);

            // 4. 熟悉度分数 (不太熟悉的单词优先)
            StudyRecord record = studyRecordMap.get(word.getCode());
            double familiarityScore = calculateFamiliarityScore(word.getCode(), record);

            if (userInfo.isVip()) {
                // VIP用户特有的评分指标
                double reciteScore = calculateReciteScore(word.getCode(), reciteInfoMap);
                double checkInScore = calculateCheckInScore(word.getCode(), checkInInfoMap);
                double gameLevelScore = calculateGameLevelScore(userInfo.getGameLevel(), word.getWordDifficulty());

                // VIP用户综合分数
                score = mistakeScore * VIP_MISTAKE_WEIGHT +
                        stageScore * VIP_STAGE_WEIGHT +
                        difficultyScore * VIP_DIFFICULTY_WEIGHT +
                        familiarityScore * VIP_FAMILIARITY_WEIGHT +
                        reciteScore * VIP_RECITE_WEIGHT +
                        checkInScore * VIP_CHECKIN_WEIGHT +
                        gameLevelScore * VIP_GAME_LEVEL_WEIGHT;
            } else {
                // 普通用户综合分数
                score = mistakeScore * MISTAKE_WEIGHT +
                        stageScore * STAGE_WEIGHT +
                        difficultyScore * DIFFICULTY_WEIGHT +
                        familiarityScore * FAMILIARITY_WEIGHT;
            }

            scores.put(word.getCode(), score);
        }

        return scores;
    }

    // VIP用户特有评分方法

    /**
     * 计算默写相关分数
     */
    private double calculateReciteScore(long wordCode, Map<Long, ReciteInfo> reciteInfoMap) {
        if (!reciteInfoMap.containsKey(wordCode)) {
            return 0.5; // 没有默写记录的单词中等优先级
        }

        ReciteInfo info = reciteInfoMap.get(wordCode);
        // 错误率高的单词优先推荐
        if (info.getWrongCount() > 0) {
            return 1.0 - (info.getCorrectCount() / (double) info.getTotalCount());
        }
        return 0.3; // 默写正确的单词降低优先级
    }

    /**
     * 计算打卡相关分数
     */
    private double calculateCheckInScore(long wordCode, Map<Long, CheckInInfo> checkInInfoMap) {
        if (!checkInInfoMap.containsKey(wordCode)) {
            return 0.5; // 没有打卡记录的单词中等优先级
        }

        CheckInInfo info = checkInInfoMap.get(wordCode);
        // 打卡错误次数多的单词优先推荐
        if (info.getWrongCount() > 0) {
            return 1.0 - (info.getCorrectCount() / (double) info.getTotalCount());
        }
        return 0.3; // 打卡正确的单词降低优先级
    }

    /**
     * 计算游戏关卡相关分数
     */
    private double calculateGameLevelScore(int userLevel, int wordDifficulty) {
        // 用户关卡越高，推荐难度越高的单词
        double levelRatio = userLevel / 100.0; // 假设关卡数在0-100之间
        double difficultyRatio = (wordDifficulty - 1) / 2.0; // 将1-3转换为0-1

        // 计算用户关卡与单词难度的匹配度
        return 1.0 - Math.abs(levelRatio - difficultyRatio);
    }

    private double calculateStageScore(WordDao word, int userStage) {
        // 用户当前阶段单词分数最高，相邻阶段分数递减
        int stageDiff = Math.abs(word.getWordStage() - userStage);
        return 1.0 / (1 + stageDiff);
    }

    private double calculateDifficultyScore(WordDao word, UserInfo userInfo) {
        // 根据用户积分调整难度偏好
        double baseDifficulty = (4 - word.getWordDifficulty()) / 3.0; // 反转难度，1-3变为1-0

        // VIP用户或高积分用户可以挑战更难单词
        if (userInfo.isVip() || userInfo.getScore() > 1000) {
            return (word.getWordDifficulty() / 3.0); // 直接使用难度
        }

        return baseDifficulty;
    }

    private double calculateFamiliarityScore(long wordCode, StudyRecord record) {
        if (record == null) {
            return 1.0; // 未学过的单词优先
        }

        // 不熟悉的单词优先
        if (!record.isFamiliarized()) {
            return 0.8;
        }

        // 收藏的单词适当加分
        if (record.isFavorite()) {
            return 0.5;
        }

        return 0.3;
    }

    // 数据库查询方法

    /**
     * 获取VIP用户的默写信息
     */
    private Map<Long, ReciteInfo> getReciteInfo(long userId) {
        Map<Long, ReciteInfo> reciteInfoMap = new HashMap<>();

        // 查询默写详情表
        String sql = "SELECT rd.word_id, SUM(CASE WHEN rd.is_correct = 1 THEN 1 ELSE 0 END) as correct_count, " +
                "SUM(CASE WHEN rd.is_correct = 0 THEN 1 ELSE 0 END) as wrong_count, COUNT(*) as total_count " +
                "FROM recitedetail rd JOIN recitechapterrecord rcr ON rd.record_id = rcr.record_id " +
                "WHERE rcr.user_id = ? GROUP BY rd.word_id";

        try (Connection conn = DriverManager.getConnection(DB_URL, DB_USER, DB_PASSWORD);
             PreparedStatement stmt = conn.prepareStatement(sql)) {

            stmt.setLong(1, userId);
            ResultSet rs = stmt.executeQuery();

            while (rs.next()) {
                long wordId = rs.getLong("word_id");
                int correctCount = rs.getInt("correct_count");
                int wrongCount = rs.getInt("wrong_count");
                int totalCount = rs.getInt("total_count");

                reciteInfoMap.put(wordId, new ReciteInfo(correctCount, wrongCount, totalCount));
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return reciteInfoMap;
    }

    /**
     * 获取VIP用户的打卡信息
     */
    private Map<Long, CheckInInfo> getCheckInInfo(long userId) {
        Map<Long, CheckInInfo> checkInInfoMap = new HashMap<>();

        // 查询打卡记录表
        String sql = "SELECT checkrecord_code, " +
                "SUM(CASE WHEN checkrecord_is_true = 1 THEN 1 ELSE 0 END) as correct_count, " +
                "SUM(CASE WHEN checkrecord_is_true = 0 THEN 1 ELSE 0 END) as wrong_count, " +
                "COUNT(*) as total_count " +
                "FROM checkrecord WHERE checkrecord_consumer_id = ? " +
                "GROUP BY checkrecord_code";

        try (Connection conn = DriverManager.getConnection(DB_URL, DB_USER, DB_PASSWORD);
             PreparedStatement stmt = conn.prepareStatement(sql)) {

            stmt.setLong(1, userId);
            ResultSet rs = stmt.executeQuery();

            while (rs.next()) {
                long wordCode = rs.getLong("checkrecord_code");
                int correctCount = rs.getInt("correct_count");
                int wrongCount = rs.getInt("wrong_count");
                int totalCount = rs.getInt("total_count");

                checkInInfoMap.put(wordCode, new CheckInInfo(correctCount, wrongCount, totalCount));
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return checkInInfoMap;
    }


    /**
     * 获取客户端用户的基本信息
     * @param userId
     * @return
     */
    private UserInfo getUserInfo(long userId) {
        String sql = "SELECT c.consumer_id, c.consumer_stage, c.consumer_variety, c.consumer_score, c.current_level " +
                "FROM consumer c WHERE c.consumer_id = ?";

        try (Connection conn = DriverManager.getConnection(DB_URL, DB_USER, DB_PASSWORD);
             PreparedStatement stmt = conn.prepareStatement(sql)) {

            stmt.setLong(1, userId);
            ResultSet rs = stmt.executeQuery();

            if (rs.next()) {
                return new UserInfo(
                        rs.getLong("consumer_id"),
                        rs.getInt("consumer_stage"),
                        rs.getInt("consumer_variety") == 1,
                        rs.getLong("consumer_score"),
                        rs.getInt("current_level")
                );
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return null;
    }

    private List<StudyRecord> getStudyRecords(long userId) {
        List<StudyRecord> records = new ArrayList<>();
        String sql = "SELECT * FROM studyrecord WHERE studyrecord_consumer_id = ?";

        try (Connection conn = DriverManager.getConnection(DB_URL, DB_USER, DB_PASSWORD);
             PreparedStatement stmt = conn.prepareStatement(sql)) {

            stmt.setLong(1, userId);
            ResultSet rs = stmt.executeQuery();

            while (rs.next()) {
                records.add(new StudyRecord(
                        rs.getLong("studyrecord_code"),
                        rs.getBoolean("studyed_is_familarized"),
                        rs.getBoolean("studyed_is_favorite")
                ));
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return records;
    }

    // 数据模型类
    public static class UserInfo {
        private final long userId;
        private final int stage;
        private final boolean isVip;
        private final long score;
        private final int gameLevel;

        public UserInfo(long userId, int stage, boolean isVip, long score, int gameLevel) {
            this.userId = userId;
            this.stage = stage;
            this.isVip = isVip;
            this.score = score;
            this.gameLevel = gameLevel;
        }

        public long getUserId() { return userId; }
        public int getStage() { return stage; }
        public boolean isVip() { return isVip; }
        public long getScore() { return score; }
        public int getGameLevel() { return gameLevel; }
    }

    public static class StudyRecord {
        private final long wordCode;
        private final boolean isFamiliarized;
        private final boolean isFavorite;

        public StudyRecord(long wordCode, boolean isFamiliarized, boolean isFavorite) {
            this.wordCode = wordCode;
            this.isFamiliarized = isFamiliarized;
            this.isFavorite = isFavorite;
        }

        public long getWordCode() { return wordCode; }
        public boolean isFamiliarized() { return isFamiliarized; }
        public boolean isFavorite() { return isFavorite; }
    }

    // VIP用户特有数据模型

    //默写数据记录
    public static class ReciteInfo {
        private final int correctCount;
        private final int wrongCount;
        private final int totalCount;

        public ReciteInfo(int correctCount, int wrongCount, int totalCount) {
            this.correctCount = correctCount;
            this.wrongCount = wrongCount;
            this.totalCount = totalCount;
        }

        public int getCorrectCount() { return correctCount; }
        public int getWrongCount() { return wrongCount; }
        public int getTotalCount() { return totalCount; }
    }

    //打卡记录
    public static class CheckInInfo {
        private final int correctCount;
        private final int wrongCount;
        private final int totalCount;

        public CheckInInfo(int correctCount, int wrongCount, int totalCount) {
            this.correctCount = correctCount;
            this.wrongCount = wrongCount;
            this.totalCount = totalCount;
        }

        public int getCorrectCount() { return correctCount; }
        public int getWrongCount() { return wrongCount; }
        public int getTotalCount() { return totalCount; }
    }
}

/**
 *  增强版单词推荐系统算法解析 (VIP用户专属)
 *
 * 这个增强版单词推荐系统在原有基础上，为VIP用户增加了更多维度的推荐指标，提供更加个性化的单词推荐服务。
 *
 * VIP用户新增推荐指标：
 *
 * 1. 默写记录分析(10%权重)：
 *    - 分析用户在默写练习中的表现
 *    - 优先推荐默写错误率高的单词
 *    - 考虑默写正确率随时间的变化
 *
 * 2. 打卡记录分析(5%权重)：
 *    - 分析用户日常打卡中的错误单词
 *    - 优先推荐打卡时经常出错的单词
 *    - 考虑打卡正确率的变化趋势
 *
 * 3. 游戏关卡适配(5%权重)：
 *    - 根据用户当前游戏关卡数调整难度
 *    - 高关卡用户会获得更多高难度单词
 *    - 实现游戏进度与单词学习的联动
 *
 * 权重分配调整：
 *    - 降低错误单词权重(40% → 35%)
 *    - 增加难度权重(10% → 15%)
 *    - 新增指标共占20%权重
 *
 * 这套增强版算法通过整合用户的多维度学习数据，为VIP用户提供更加精准和个性化的单词推荐服务，
 * 帮助VIP用户更高效地提升英语词汇量。
 */